package com.cby.android.base.net;

import com.cby.android.base.net.ssl.HttpsHostnameVerifier;
import com.cby.android.base.net.ssl.HttpsSSLSocketFactory;

import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

/**
 * @description: DownHelper--并发分段下载
 * @author: ChenBaoYang
 * @createDate: 2022/8/22 11:01 上午
 */
public class DownHelper extends Thread{

    /**
     * 定义下载的资源路径
     */
    private String path;

    /**
     * 指定所下载的文件的保存位置
     */
    private String targetFile;

    /**
     * 定义所需要多少个线程进行资源下载
     */
    private int threadNum;

    /**
     * 定义下载的线程对象数组
     */
    private DownloadThread[] threads;

    /**
     * 定义下载的文件的总大小
     */
    private int fileSize;

    public DownHelper(String path , String targetFile, int threadNum){
        this.path = path;
        this.threadNum = threadNum;
        // 初始化 threads数组
        threads = new DownloadThread[threadNum];
        this.targetFile = targetFile;
    }

    @Override
    public void run() {
        try {
            download();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void download() throws Exception {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //添加https的认证
        if (path.toUpperCase().startsWith("HTTPS")) {
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) conn;
            httpsURLConnection.setHostnameVerifier(new HttpsHostnameVerifier());
            httpsURLConnection.setSSLSocketFactory(HttpsSSLSocketFactory.factory());
            conn = httpsURLConnection;
        }
        conn.setConnectTimeout(5 * 1000) ;
        conn.setRequestMethod("GET") ;
        conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/" +
                        "x-shockwaveflash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
        conn.setRequestProperty("Accept-Language" , "zh-CN");
        conn.setRequestProperty("Charset" , "UTF一8" );
        conn.setRequestProperty("User-Agent" , "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; Trident/4.0; NET CLR 1.1. 4322; .NET CLR 2..0.50727; .NET CLR 3.0.04506 . 30; .NET CLR 3.0.4506 .2152; .NET CLR 3.5 .30729)") ;
        conn.setRequestProperty("Connection", "Keep-Alive");
        //得到文件大小
        fileSize = conn.getContentLength() ;
        conn.disconnect();
        int currentPartSize = fileSize / threadNum + 1;
        RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
        //设置本地文件的大小
        file.setLength(fileSize);
        file.close();
        for (int i = 0; i < threadNum; i++)
        {
            //计算每条线程的下载的开始位置
            int startPos = i * currentPartSize;
            //每个钱程使用一个 RandomAccessFile 进行下载
            RandomAccessFile currentPart = new RandomAccessFile(targetFile, "rw");
            //定位该线程的下载位置
            currentPart.seek(startPos);
            //创建下载线程
            threads[i] = new DownloadThread(startPos, currentPartSize, currentPart);
            //启动下载编程
            threads[i].start();
        }
    }

    /**
     * 获取下戴的完成百分比
     * @return
     */
    public double getCompleteRate(){
        // 统计多条线程已经下貌的总大小
        int sumSize = 0;
        for (int i = 0; i < threadNum; i++){
            //返回已经完成的百分比
            if(threads[i] != null) {
                sumSize += threads[i].length;
            }

        }

        return sumSize * 1.0 / fileSize;
    }


    private class DownloadThread extends Thread {
        //当前线程的下载位置
        private final int startPos;
        //定义当前线程负责下载的文件大小
        private final int currentPartSize;
        //当前线程需要下载的文件块
        private RandomAccessFile currentPart;
        //定义已经该线程已下载的字节数
        public int length;

        public DownloadThread(int startPos, int currentPartSize,
                              RandomAccessFile currentPart) {
            this.startPos = startPos;
            this.currentPartSize = currentPartSize;
            this.currentPart = currentPart;
        }

        @Override
        public void run() {
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5 * 1000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty("Accept", "image/gif,image/ipeg,image/pjpeg,image/pjpeg, application/x-shockwave-flash，application/xaml+xml, application/vnd.ms-xpsdocument，application/x-ms-xbap application/x-ms-app lication,application/vnd.ms-excel application/vnd.ms-powerpoint,application/ msword，*/*");
                conn.setRequestProperty("Accept-Language", "zh-CN");
                conn.setRequestProperty("Charset", "UTF-8");
                InputStream inStream = conn.getInputStream();
                //跳过startPos个字节，表明该线程只下载自己负责哪部分文
                inStream.skip(this.startPos);
                byte[] buffer = new byte[1024];
                int hasRead = 0;
                //读取网络数据，并写入本地文件
                while (length < currentPartSize && (hasRead = inStream.read(buffer)) != -1) {
                    currentPart.write(buffer, 0, hasRead);
                    //该线程下载的总大小
                    length += hasRead;
                }
                currentPart.close();
                inStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


